/**
 * 文件分片上传服务器
 * 处理文件分片的接收、合并和状态管理
 */

const express = require("express");
const multer = require("multer");
const cors = require("cors");
const fs = require("fs");
const path = require("path");
const { promisify } = require("util");
const textInfo = require("./text/index.js");
const WebSocket = require("ws");

// 创建Express应用
const app = express();
const port = 3000;

// 中间件配置
app.use(cors()); // 允许跨域请求
app.use(express.urlencoded({ extended: true }));
app.use(express.json()); // 解析JSON请求体

// 创建上传目录
const uploadsDir = path.join(__dirname, "uploads");
const chunksDir = path.join(uploadsDir, "chunks");
const filesDir = path.join(uploadsDir, "files");

// 确保目录存在
[uploadsDir, chunksDir, filesDir].forEach((dir) => {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
});

// 上传状态记录
const uploadStatus = {};

// 配置multer存储
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, chunksDir);
  },
  filename: (req, file, cb) => {
    // 使用时间戳作为临时文件名
    const timestamp = Date.now();

    cb(null, `temp-${timestamp}`);
  },
});

const upload = multer({ storage });

// 上传分片接口
app.post("/api/upload/chunk", upload.single("chunk"), async (req, res) => {
  try {
    const { fileId, chunkIndex, totalChunks, filename } = req.body;

    // 初始化或更新上传状态
    if (!uploadStatus[fileId]) {
      uploadStatus[fileId] = {
        filename,
        totalChunks: parseInt(totalChunks),
        uploadedChunks: new Array(parseInt(totalChunks)).fill(false),
        chunkPaths: new Array(parseInt(totalChunks)).fill(""), // 存储分片路径
        status: "uploading",
      };
    }

    // 生成最终的分片文件路径
    const chunkPath = path.join(chunksDir, `${fileId}-${chunkIndex}`);
    uploadStatus[fileId].chunkPaths[parseInt(chunkIndex)] = chunkPath;
    uploadStatus[fileId].uploadedChunks[parseInt(chunkIndex)] = true;

    // 计算上传进度
    const uploadedCount =
      uploadStatus[fileId].uploadedChunks.filter(Boolean).length;
    const progress = Math.floor((uploadedCount / parseInt(totalChunks)) * 100);

    // 将临时文件重命名为正确的分片文件名
    const file = req.file;
    fs.renameSync(file.path, chunkPath);

    // 检查是否所有分片都已上传完成
    if (uploadStatus[fileId].uploadedChunks.every(Boolean)) {
      // 所有分片上传完成，更新状态
      uploadStatus[fileId].status = "uploaded";
    }
    res.status(200).json({
      success: true,
      message: "分片上传成功",
      progress,
    });
  } catch (error) {
    console.error("分片上传失败:", error);
    res.status(500).json({
      success: false,
      message: `分片上传失败: ${error.message}`,
    });
  }
});

// 合并分片接口
app.post("/api/upload/merge", async (req, res) => {
  try {
    const { fileId } = req.body;
    const status = uploadStatus[fileId];

    if (!status) {
      console.error(`合并失败: 找不到文件ID ${fileId} 的上传记录`);
      return res.status(404).json({
        success: false,
        message: "找不到上传记录",
      });
    }

    // 检查是否所有分片都已上传
    const allUploaded = status.uploadedChunks.every(Boolean);
    const missingChunks = status.uploadedChunks
      .map((uploaded, index) => (!uploaded ? index : -1))
      .filter((index) => index !== -1);

    if (!allUploaded) {
      console.error(
        `合并失败: 文件 ${fileId} 的分片未完整上传，缺失分片索引:`,
        missingChunks
      );
      return res.status(400).json({
        success: false,
        message: `有分片尚未上传完成，缺失分片: ${missingChunks.join(", ")}`,
      });
    }

    // 生成唯一的文件名
    const fileExt = path.extname(status.filename);
    const fileName = `${fileId}${fileExt}`;
    const filePath = path.join(filesDir, fileName);

    // 检查目标目录是否可写
    try {
      await promisify(fs.access)(filesDir, fs.constants.W_OK);
    } catch (error) {
      console.error(`合并失败: 目标目录 ${filesDir} 没有写入权限:`, error);
      return res.status(500).json({
        success: false,
        message: "服务器存储目录无写入权限",
      });
    }

    // 创建写入流
    const writeStream = fs.createWriteStream(filePath);

    // 按顺序合并分片
    for (let i = 0; i < status.totalChunks; i++) {
      const chunkPath = status.chunkPaths[i];

      // 检查分片文件是否存在
      if (!fs.existsSync(chunkPath)) {
        console.error(`合并失败: 分片文件不存在 ${chunkPath}`);
        return res.status(500).json({
          success: false,
          message: `分片文件 ${i} 丢失`,
        });
      }

      try {
        const chunkBuffer = await promisify(fs.readFile)(chunkPath);
        writeStream.write(chunkBuffer);

        // 删除已合并的分片
        await promisify(fs.unlink)(chunkPath);
      } catch (error) {
        console.error(`合并失败: 处理分片 ${i} 时发生错误:`, error);
        return res.status(500).json({
          success: false,
          message: `处理分片 ${i} 失败: ${error.message}`,
        });
      }
    }

    writeStream.end();

    // 等待写入完成
    await new Promise((resolve, reject) => {
      writeStream.on("finish", () => {
        console.log(`文件 ${fileId} 合并完成，保存至 ${filePath}`);
        resolve();
      });
      writeStream.on("error", (error) => {
        console.error(`合并失败: 写入最终文件时发生错误:`, error);
        reject(error);
      });
    });

    // 更新状态
    status.status = "completed";
    status.filePath = filePath;

    res.status(200).json({
      success: true,
      message: "文件合并成功",
      fileName,
      filePath: `/api/files/${fileName}`, // 提供文件访问路径
    });
  } catch (error) {
    console.error("文件合并失败:", error);
    res.status(500).json({
      success: false,
      message: `文件合并失败: ${error.message}`,
    });
  }
});

// 获取上传状态接口
app.get("/api/upload/status", (req, res) => {
  try {
    const { fileId } = req.query;

    if (!fileId || !uploadStatus[fileId]) {
      return res.status(404).json({
        success: false,
        message: "找不到上传记录",
      });
    }

    const status = uploadStatus[fileId];
    const uploadedCount = status.uploadedChunks.filter(Boolean).length;
    const progress = Math.floor((uploadedCount / status.totalChunks) * 100);

    res.status(200).json({
      success: true,
      fileId,
      filename: status.filename,
      status: status.status,
      uploadedChunks: uploadedCount,
      totalChunks: status.totalChunks,
      progress,
    });
  } catch (error) {
    console.error("获取上传状态失败:", error);
    res.status(500).json({
      success: false,
      message: `获取上传状态失败: ${error.message}`,
    });
  }
});

// 取消上传接口
app.post("/api/upload/cancel", (req, res) => {
  try {
    const { fileId } = req.body;

    if (!fileId || !uploadStatus[fileId]) {
      return res.status(404).json({
        success: false,
        message: "找不到上传记录",
      });
    }

    // 删除已上传的分片
    const status = uploadStatus[fileId];

    for (let i = 0; i < status.totalChunks; i++) {
      const chunkPath = path.join(chunksDir, `${fileId}-${i}`);
      if (fs.existsSync(chunkPath)) {
        fs.unlinkSync(chunkPath);
      }
    }

    // 删除上传记录
    delete uploadStatus[fileId];

    res.status(200).json({
      success: true,
      message: "上传已取消",
    });
  } catch (error) {
    console.error("取消上传失败:", error);
    res.status(500).json({
      success: false,
      message: `取消上传失败: ${error.message}`,
    });
  }
});

// 提供文件访问接口
app.get("/api/files/:fileName", (req, res) => {
  try {
    const { fileName } = req.params;
    const filePath = path.join(filesDir, fileName);

    if (!fs.existsSync(filePath)) {
      return res.status(404).json({
        success: false,
        message: "文件不存在",
      });
    }

    res.sendFile(filePath);
  } catch (error) {
    console.error("文件访问失败:", error);
    res.status(500).json({
      success: false,
      message: `文件访问失败: ${error.message}`,
    });
  }
});

function splitByLength(str, len = 100) {
  if (!str) return;
  const chars = Array.from(str.trim());
  const result = [];
  for (let i = 0; i < chars.length; i += len) {
    result.push(
      chars
        .slice(i, i + len)
        .join("")
        .replace(/\s+/g, "")
    );
  }
  return result;
}
let interval = null;
//流式对话接口
app.post("/api/chat", async (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  res.write("retry: 3000\n\n");
  const messages = splitByLength(textInfo.default.backMessage, 100);
  let i = 0;
  interval = setInterval(() => {
    if (i < messages.length) {
      console.log("messages[i]", messages[i]);
      res.write(`data: ${messages[i]}\n\n`);
      i++;
    } else {
      clearInterval(interval);
      res.write(`event: end\ndata: done\n\n`);
      res.end();
    }
  }, 1000);
});

// 终止流式对话接口
app.post("/api/chat/stop", (req, res) => {
  try {
    // 获取当前活跃的interval
    if (interval) {
      clearInterval(interval);
      res.status(200).json({
        success: true,
        message: "流式对话已终止",
      });
    } else {
      res.status(404).json({
        success: false,
        message: "没有找到活跃的对话",
      });
    }
  } catch (error) {
    console.error("终止流式对话失败:", error);
    res.status(500).json({
      success: false,
      message: `终止流式对话失败: ${error.message}`,
    });
  }
});

// 启动服务器
app.listen(port, () => {
  console.log(`文件上传服务器运行在 http://localhost:${port}`);
});

// 修改WebSocket服务器代码

// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });

// 存储用户连接和匹配状态
const clients = new Map();
const waitingUsers = new Set(); // 等待匹配的用户
const matches = new Map(); // 存储匹配关系

wss.on('connection', (ws) => {
  let userId = null;
  let userName = null;

  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);
      
      // 处理用户连接
      if (data.type === 'connect') {
        userId = data.userId;
        userName = data.userName;
        clients.set(userId, { ws, userName });
        
        // 发送欢迎消息
        ws.send(JSON.stringify({
          type: 'system',
          content: '连接成功，等待匹配...',
          timestamp: Date.now()
        }));
        
        // 尝试匹配
        matchUsers(userId);
      }
      
      // 处理聊天消息
      else if (data.type === 'chat') {
        const matchedUserId = matches.get(userId);
        if (matchedUserId) {
          const matchedUser = clients.get(matchedUserId);
          if (matchedUser && matchedUser.ws.readyState === WebSocket.OPEN) {
            matchedUser.ws.send(JSON.stringify({
              type: 'message',
              content: data.content,
              userName: userName,
              timestamp: Date.now()
            }));
          }
        }
      }
      
      // 处理重新匹配请求
      else if (data.type === 'rematch') {
        const currentMatch = matches.get(userId);
        if (currentMatch) {
          // 通知当前匹配对象连接已断开
          const matchedUser = clients.get(currentMatch);
          if (matchedUser && matchedUser.ws.readyState === WebSocket.OPEN) {
            matchedUser.ws.send(JSON.stringify({
              type: 'system',
              content: '对方请求重新匹配',
              timestamp: Date.now()
            }));
          }
          // 解除匹配
          matches.delete(userId);
          matches.delete(currentMatch);
        }
        // 重新进入匹配队列
        matchUsers(userId);
      }
      
    } catch (error) {
      console.error('处理WebSocket消息时出错:', error);
    }
  });

  ws.on('close', () => {
    if (userId) {
      handleDisconnect(userId);
    }
  });
});

// 匹配用户
function matchUsers(userId) {
  // 如果用户已经在等待队列中，直接返回
  if (waitingUsers.has(userId)) return;
  
  // 如果有其他用户在等待，进行匹配
  if (waitingUsers.size > 0) {
    const iterator = waitingUsers.values();
    const matchedUserId = iterator.next().value;
    
    // 确保匹配用户仍然在线
    const matchedUser = clients.get(matchedUserId);
    const currentUser = clients.get(userId);
    
    if (matchedUser && currentUser) {
      // 建立匹配关系
      matches.set(userId, matchedUserId);
      matches.set(matchedUserId, userId);
      
      // 从等待队列中移除
      waitingUsers.delete(matchedUserId);
      
      // 通知双方匹配成功
      const matchSuccessMsg = JSON.stringify({
        type: 'system',
        content: '匹配成功！开始聊天吧',
        timestamp: Date.now()
      });
      
      matchedUser.ws.send(matchSuccessMsg);
      currentUser.ws.send(matchSuccessMsg);
    }
  } else {
    // 如果没有其他用户，加入等待队列
    waitingUsers.add(userId);
  }
}

// 处理用户断开连接
function handleDisconnect(userId) {
  // 清理匹配关系
  const matchedUserId = matches.get(userId);
  if (matchedUserId) {
    const matchedUser = clients.get(matchedUserId);
    if (matchedUser && matchedUser.ws.readyState === WebSocket.OPEN) {
      matchedUser.ws.send(JSON.stringify({
        type: 'system',
        content: '对方已断开连接',
        timestamp: Date.now()
      }));
    }
    matches.delete(userId);
    matches.delete(matchedUserId);
  }
  
  // 清理等待队列
  waitingUsers.delete(userId);
  
  // 清理客户端连接
  clients.delete(userId);
}
